Friend NotInheritable Class libGraph2D

    Private mItems As New Collection
    Private mAntiAlias As Boolean = True

    Private mMin As Long = 0
    Private mMax As Long = 100
    Private mItemColours() As Color
    Private mScrollBars As ScrollBars = ScrollBars.None
    Private mGraphArea As Rectangle = Me.ClientRectangle
    Private mCursorX As Long = -1
    Private mTrackX As Long = -1
    Private mRangeX As Long = 100
    Private mStreamMax As Long = 0
    Private mHighDetail As Boolean = False
    Private mMenuItems As New Collection

    Private mSelectMin As PointF = Nothing
    Private mSelectMax As PointF = Nothing
    Private mSelectMode As Boolean = False

    Private mGraphicManager As BufferedGraphicsContext
    Private mLegendBuffer As BufferedGraphics
    Private mBackgroundBuffer As BufferedGraphics
    Private mGraphBuffer As BufferedGraphics

    Private mBgColour As Color = Color.LightBlue
    Private mBgGradient As Color = Color.WhiteSmoke
    Private mSelectionColour As Color = Color.FromArgb(128, Color.Silver)

    ''' <summary>
    ''' On selection changed event (mouse selection)
    ''' </summary>
    ''' <param name="Graph2D"></param>
    ''' <param name="pX1">Point X (Lower) in terms of the index of the original Consult_Args</param>
    ''' <param name="pX2">Point X (Upper) in terms of the index of the original Consult_Args</param>
    ''' <remarks></remarks>
    Event onSelectionChanged(ByVal Graph2D As libGraph2D, ByVal pX1 As Long, ByVal pX2 As Long)
    ''' <summary>
    ''' On Delete Selection event (key press or mouse event)
    ''' </summary>
    ''' <param name="Graph2D">This...</param>
    ''' <param name="pX1">Point X (Lower) in terms of the index of the original Consult_Args</param>
    ''' <param name="pX2">Point X (Upper) in terms of the index of the original Consult_Args</param>
    ''' <remarks></remarks>
    Event onDeleteSelection(ByVal Graph2D As libGraph2D, ByVal pX1 As Long, ByVal pX2 As Long)

    Friend Enum ScrollBars As Byte
        None = 0
        Both = 3
        TrackLR = 1
        ZoomLR = 2
    End Enum

    Sub New()
        ' This call is required by the Windows Form Designer.
        InitializeComponent()
        Me.DoubleBuffered = True
        mItems = New Collection()
        mItemColours = New Color() {Color.Beige, Color.DarkBlue, Color.DarkGreen, Color.DarkOrange, Color.DarkViolet, Color.DarkRed, Color.DarkCyan}
        CheckScrolls()

        For Each item As ToolStripMenuItem In Me.cmSelectItems.Items

        Next
        ' Add any initialization after the InitializeComponent() call.

        mGraphicManager = BufferedGraphicsManager.Current
        mGraphicManager.MaximumBuffer = New Size(Me.Width + 1, Me.Height + 1)
        mBackgroundBuffer = mGraphicManager.Allocate(Me.CreateGraphics, mGraphArea)
        DrawBackground(mBackgroundBuffer.Graphics)
    End Sub

    Friend Sub AddPoint(ByVal Key As String, ByVal point As PointF)
        ' check if the item already exists, if so append to it
        If mItems.Contains(LCase(Key)) Then
            CType(mItems.Item(LCase(Key)), libGraph2Ditems).Add(point)
        Else ' item doesn't exist. create new
            ' check if ok to add. then do so
            'If mItems.Count < 10 Then
            InitItem(Key)
            If mItems.Contains(LCase(Key)) Then
                CType(mItems.Item(LCase(Key)), libGraph2Ditems).Add(point)
            End If
            'End If
        End If
    End Sub
    Friend Sub AddCursor(ByVal Key As String, ByVal point As PointF, Optional ByVal text As String = "")
        If mItems.Contains(LCase(Key)) Then
            CType(mItems.Item(LCase(Key)), libGraph2Ditems).setCursor(point, text)
        End If
    End Sub
    Friend Sub AddDataStream(ByRef stream As DataLogging.ConsultLog)
        For Each item As Consult_Args In stream
            AddDataItem(item)
        Next
        Me.Refresh()
    End Sub
    Friend Sub AddDataItem(ByRef stream As Consult_Args)
        mStreamMax = stream.Index
        Dim fStr As String
        For Each item As ToolStripMenuItem In cmSelectItems.Items
            fStr = LCase(CType(item.Tag, String))
            Dim value As Object = stream(fStr)
            If Not IsNothing(value) Then
                AddPoint(fStr, New PointF(stream.Index, value))
            End If
        Next
    End Sub

    Private Sub sbTrackSetRange()
        If mStreamMax >= 2 Then
            sbTrack.Maximum = mStreamMax '50 * (CDbl(mStreamMax) \ CDbl(mRangeX))
            sbTrack.Minimum = mRangeX
            sbTrack.Value = sbTrack.Maximum
            If sbTrack.Minimum > sbTrack.Maximum Then
                sbTrack.Enabled = False
            Else
                sbTrack.Enabled = True
            End If
        Else
            sbTrack.Enabled = False
        End If
    End Sub
    Private Sub sbTrack_Scroll(ByVal sender As System.Object, ByVal e As System.Windows.Forms.ScrollEventArgs) Handles sbTrack.Scroll
        If sbTrack.Maximum > 0 Then
            Me.TrackX = (sbTrack.Value / sbTrack.Maximum) * mStreamMax
            setLeft(True)
        End If
    End Sub
    Private Sub sbZoom_Scroll(ByVal sender As System.Object, ByVal e As System.Windows.Forms.ScrollEventArgs) Handles sbZoom.Scroll
        Range = sbZoom.Value * CInt(sbZoom.Tag)
        sbTrack.LargeChange = sbZoom.Value
    End Sub

    Private Sub InitItem(ByVal Key As String)
        Dim fAdd As New libGraph2Ditems()
        'me.cmMDisplay.DropDownItems(
        fAdd.Max = Consult_Args.itemMax(Key)
        fAdd.Width = 1
        fAdd.Min = Consult_Args.itemMin(Key)
        fAdd.Name = Consult_Args.itemName(Key)
        fAdd.Colour = Consult_Args.itemColour(Key)
        If mMenuItems.Contains(Key) Then
            fAdd.Display = True
            If CType(mMenuItems(Key), CheckState) = CheckState.Indeterminate Then
                fAdd.CursorMode = True
            End If
        End If

        If fAdd.Name <> "" Then
            mItems.Add(fAdd, LCase(Key))
        End If
    End Sub
    Private Sub CheckScrolls()
        If Me.ClientSize.Width >= 1 And Me.ClientSize.Height >= 1 Then
            mGraphArea.Width = Me.ClientSize.Width
            mGraphArea.Height = Me.ClientSize.Height
            If mScrollBars = ScrollBars.None Then
                Me.sbTrack.Visible = False
                Me.sbZoom.Visible = False
            Else
                If mScrollBars And ScrollBars.TrackLR Then
                    Me.sbTrack.Visible = True
                    mGraphArea.Height -= sbTrack.Height
                Else
                    Me.sbTrack.Visible = False
                End If
                If mScrollBars And ScrollBars.ZoomLR Then
                    Me.sbZoom.Visible = True
                    mGraphArea.Width -= sbZoom.Width
                Else
                    Me.sbZoom.Visible = False
                End If
            End If
        End If
    End Sub

    Public Property AntiAlias() As Boolean
        Get
            Return mAntiAlias
        End Get
        Set(ByVal value As Boolean)
            mAntiAlias = value
            Me.Refresh()
        End Set
    End Property
    Public Property bgColour() As Color
        Get
            Return mBgColour
        End Get
        Set(ByVal value As Color)
            mBgColour = value
            If Not IsNothing(mBackgroundBuffer) Then DrawBackground(mBackgroundBuffer.Graphics)
            Me.Refresh()
        End Set
    End Property
    Public Property bgGradientColour() As Color
        Get
            Return mBgGradient
        End Get
        Set(ByVal value As Color)
            mBgGradient = value
            If Not IsNothing(mBackgroundBuffer) Then DrawBackground(mBackgroundBuffer.Graphics)
            Me.Refresh()
        End Set
    End Property
    Public Property DisplayScrolBars() As ScrollBars
        Get
            Return mScrollBars
        End Get
        Set(ByVal value As ScrollBars)
            mScrollBars = value
            CheckScrolls()
            Me.Refresh()
        End Set
    End Property
    Public Property CursorX() As Long
        Get
            Return mCursorX
        End Get
        Set(ByVal value As Long)
            mCursorX = value
            ' If value >= 0 And value >= mMin And value <= mMax Then
            '  Me.Refresh()
            ' End If
        End Set
    End Property
    Public Property TrackX() As Long
        Get
            Return mTrackX
        End Get
        Set(ByVal value As Long)
            mTrackX = value
        End Set
    End Property
    Public Property Range() As Long
        Get
            Return mRangeX
        End Get
        Set(ByVal value As Long)
            If Range / CInt(sbZoom.Tag) > sbZoom.Minimum And _
                Range / CInt(sbZoom.Tag) <= sbZoom.Maximum Then
                sbZoom.Value = Range / CInt(sbZoom.Tag)
            End If
            mRangeX = value
            sbTrackSetRange()
            setLeft()
        End Set
    End Property
    Public Property HighDetail() As Boolean
        Get
            Return mHighDetail
        End Get
        Set(ByVal value As Boolean)
            mHighDetail = value
        End Set
    End Property
    Public Property DisplayDefaults() As String
        Get
            Dim f_string As String = ""
            For Each item As ToolStripMenuItem In Me.cmSelectItems.Items
                If mMenuItems.Contains(CType(item.Tag, String)) Then
                    If CType(mMenuItems(CType(item.Tag, String)), CheckState) = CheckState.Indeterminate Then
                        f_string &= CType(item.Tag, String) & "*|"
                    Else
                        f_string &= CType(item.Tag, String) & "|"
                    End If
                End If
            Next

            Return f_string
        End Get
        Set(ByVal value As String)
            If Not IsNothing(value) AndAlso value <> "" Then
                mMenuItems.Clear()
                Dim f_strings() As String = Split(value, "|")
                For Each str As String In f_strings
                    If str <> "" Then
                        If InStr(str, "*") Then
                            mMenuItems.Add(CheckState.Indeterminate, Replace(str, "*", ""))
                        Else
                            mMenuItems.Add(CheckState.Checked, Replace(str, "*", ""))
                        End If
                    End If
                Next
                'Refresh all the Display Defaults here
                setMenuItems()
            End If
        End Set
    End Property
    Private Sub setMenuItems()
        For Each item As ToolStripMenuItem In Me.cmSelectItems.Items
            If mMenuItems.Contains(CType(item.Tag, String)) Then
                item.CheckState = CheckState.Checked
                If CType(mMenuItems(CType(item.Tag, String)), CheckState) = CheckState.Indeterminate Then
                    item.CheckState = CheckState.Indeterminate
                End If
            Else
                item.CheckState = CheckState.Unchecked
            End If
        Next
    End Sub
    Public ReadOnly Property selectionMin() As Long
        Get
            Return mSelectMin.X
        End Get
    End Property
    Public ReadOnly Property selectionMax() As Long
        Get
            Return mSelectMax.X
        End Get
    End Property

    Public Property SelectMode() As Boolean
        Get
            Return mSelectMode
        End Get
        Set(ByVal value As Boolean)
            mSelectMode = value
            If value = False Then
                mSelectMin = Nothing
                mSelectMax = Nothing
                Me.Refresh()
            End If
        End Set
    End Property
    Private Sub setSelection(ByRef point1 As Point)
        If Not IsNothing(point1) Then
            If SelectMode Then
                mSelectMin = New PointF((((CSng(point1.X) / CSng(mGraphArea.Width)) * CSng(mMax - mMin)) + mMin) / 1.0!, 0)
            Else
                mCursorX = (((CSng(point1.X) / CSng(mGraphArea.Width)) * CSng(mMax - mMin)) + mMin) / 1.0!
                Me.Refresh()
                RaiseEvent onSelectionChanged(Me, mCursorX, mCursorX)
            End If
        End If
    End Sub
    Private Sub setSelection2(ByRef point2 As Point)
        If Not IsNothing(point2) Then
            mSelectMax = New PointF((((CSng(point2.X) / CSng(mGraphArea.Width)) * CSng(mMax - mMin)) + mMin) / 1.0!, 0)
        End If
    End Sub

    Protected Overrides Sub OnMouseDown(ByVal e As System.Windows.Forms.MouseEventArgs)
        If e.Button = Windows.Forms.MouseButtons.Left Then
            setSelection(e.Location)
        End If
        MyBase.OnMouseDown(e)
    End Sub
    Protected Overrides Sub OnMouseUp(ByVal e As System.Windows.Forms.MouseEventArgs)
        If e.Button = Windows.Forms.MouseButtons.Left Then
            If SelectMode Then
                setSelection2(e.Location)
                If Not IsNothing(mSelectMin) And Not IsNothing(mSelectMax) Then
                    Me.Refresh()
                    If mSelectMax.X < mSelectMin.X Then
                        Dim f_tmp As PointF = mSelectMax
                        mSelectMax = mSelectMin
                        mSelectMin = f_tmp
                    End If
                    RaiseEvent onSelectionChanged(Me, mSelectMin.X, mSelectMax.X)
                End If
            End If
        End If
        MyBase.OnMouseUp(e)
    End Sub
    Protected Overrides Sub OnMouseMove(ByVal e As System.Windows.Forms.MouseEventArgs)
        MyBase.OnMouseMove(e)
        If e.Button = Windows.Forms.MouseButtons.Left Then
            If SelectMode Then
                setSelection2(e.Location)
                If Not IsNothing(mSelectMin) And Not IsNothing(mSelectMax) Then Me.Refresh()
            Else
                setSelection(e.Location)
                If e.X <= 0 Then
                    trackLeft()
                ElseIf e.X > mGraphArea.Width Then
                    trackRight()
                End If
            End If
            If e.Y <= 0 Then
                Debug.Print("zoom in")
                zoomIn()
            ElseIf e.Y >= mGraphArea.Height Then
                Debug.Print("zoom out")
                zoomOut()
            End If
        End If
    End Sub
    Protected Overrides Sub OnKeyPress(ByVal e As System.Windows.Forms.KeyPressEventArgs)
        MyBase.OnKeyPress(e)
        If e.KeyChar = "z" Then
            If Not IsNothing(mSelectMin) And Not IsNothing(mSelectMax) Then
                If mSelectMin.X < mSelectMax.X Then
                    mMin = mSelectMin.X
                    mMax = mSelectMax.X
                    Me.Refresh()
                Else
                    mMax = mSelectMin.X
                    mMin = mSelectMax.X
                    Me.Refresh()
                End If
            End If
        End If
    End Sub

    Private Sub trackLeft()
        If sbTrack.Value >= sbTrack.Minimum + sbTrack.LargeChange Then
            sbTrack.Value -= sbTrack.LargeChange
            Me.sbTrack_Scroll(sbTrack, Nothing)
        End If
    End Sub
    Private Sub trackRight()
        If sbTrack.Value <= sbTrack.Maximum - sbTrack.LargeChange Then
            sbTrack.Value += sbTrack.LargeChange
            Me.sbTrack_Scroll(sbTrack, Nothing)
        End If
    End Sub
    Private Sub zoomIn()
        If sbZoom.Value < sbZoom.Maximum Then
            sbZoom.Value += 1
            Me.sbZoom_Scroll(sbZoom, Nothing)
            ' Me.setRight()
        End If
    End Sub
    Private Sub zoomOut()
        If sbZoom.Value > sbZoom.Minimum Then
            sbZoom.Value -= 1
            Me.sbZoom_Scroll(sbZoom, Nothing)
            '  Me.setRight()
        End If
    End Sub

    Friend Sub Clear()
        If Not IsNothing(mItems) Then
            For Each item As libGraph2Ditems In mItems
                item.Clear()
            Next
        End If
        Me.Refresh()
    End Sub
    Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
        If Me.Visible Then
            MyBase.OnPaint(e)
            mBackgroundBuffer.Render(e.Graphics)
            DrawPoints(e.Graphics)
            DrawSelection(e)
            DrawLedgend(e.Graphics)
        End If
        'Debug.Print("Painting 2d graph")
    End Sub
    Public Overrides Sub Refresh()
        'sbTrackSetRange()
        MyBase.Refresh()
    End Sub
    Protected Overrides Sub OnResize(ByVal e As System.EventArgs)
        MyBase.OnResize(e)
        CheckScrolls()
        ' DrawBackground(mBackgroundBuffer.Graphics)
        mGraphicManager = BufferedGraphicsManager.Current
        mGraphicManager.MaximumBuffer = New Size(mGraphArea.Width + 1, mGraphArea.Height + 1)
        mBackgroundBuffer = mGraphicManager.Allocate(Me.CreateGraphics, mGraphArea)
        DrawBackground(mBackgroundBuffer.Graphics)
        Me.Refresh()
    End Sub

    Private Sub DrawBackground(ByRef g As Graphics)
        Dim a As New System.Drawing.Drawing2D.LinearGradientBrush(New RectangleF(0, 0, Me.mGraphArea.Width, Me.mGraphArea.Height), mBgColour, mBgGradient, LinearGradientMode.ForwardDiagonal)
        Dim p As New Pen(Brightness(bgColour, 75))
        g.FillRectangle(a, New Rectangle(1, 1, Me.mGraphArea.Width - 1, Me.mGraphArea.Height - 1))
        g.DrawRectangle(p, New Rectangle(0, 0, Me.mGraphArea.Width - 1, Me.mGraphArea.Height - 1))
        a.Dispose()
        p.Dispose()
    End Sub
    Private Sub DrawPoints(ByRef g As Graphics)
        Dim fColour As Color
        Dim fWidth As Single
        Dim fLast As PointF
        Dim fCurrent As PointF
        Dim fCHeight As Integer = Me.mGraphArea.Height
        Dim fCWidth As Integer = Me.mGraphArea.Width
        Dim fStep As Integer
        Me.SuspendLayout()

        ' dont draw over the border!
        g.Clip = New Region(New Rectangle(1, 1, Me.mGraphArea.Width - 3, Me.mGraphArea.Height - 3))
        g.InterpolationMode = InterpolationMode.NearestNeighbor
        g.SmoothingMode = SmoothingMode.HighSpeed
        Dim b As SolidBrush
        Dim p As Pen

        ' Setup the detail mode.. during playback its in low detail mode..
        If mHighDetail Then
            fStep = 1
        Else
            fStep = (((mMax - mMin) / (mGraphArea.Width / 3)) \ 1) + 1
        End If

        ' g.ScaleTransform(CSng(mGraphArea.Width) / CSng(mMax - mMin), CSng(mGraphArea.Height))
        ' g.TranslateTransform(CSng(-mMin), 0)

        If Not mItems Is Nothing AndAlso mItems.Count > 0 Then
            For Each item As libGraph2Ditems In mItems
                If item.Count >= 2 Then
                    If item.Display Then
                        fColour = item.Colour
                        b = New SolidBrush(item.Colour)
                        p = New Pen(fColour, fWidth)
                        fWidth = item.Width
                        
                        fLast = item(0)
                        For i As Long = 1 To item.Count - 1 Step fStep
                            fCurrent = item(i)
                            If item.CursorMode Then
                                If mCursorX >= mMin And mCursorX <= mMax Then
                                    If mCursorX >= fLast.X And mCursorX < fCurrent.X And mMax <> mMin Then
                                        Dim fRectF As New RectangleF(New PointF(((((fCurrent.X - mMin) / (mMax - mMin)) * fCWidth) - 2), ((fCurrent.Y) * fCHeight) - 2), New SizeF(4, 4))
                                        g.FillEllipse(b, fRectF)

                                        g.DrawString(Format((((0.95 - fCurrent.Y) / 0.95) * (item.Max - item.Min)) + item.Min, "N1"), New Font(Me.Font.FontFamily, 14, FontStyle.Regular, GraphicsUnit.Pixel), b, fRectF.X, fRectF.Y)
                                    End If
                                End If
                            End If
                            If fCurrent.X > mMin - 3 And fCurrent.X < mMax + 3 And mMax <> mMin Then
                                ' g.DrawLine(p, New PointF(fLast.X, fLast.Y), New PointF(fCurrent.X, fCurrent.Y))
                                g.DrawLine(p, New PointF((((fLast.X - mMin) / (mMax - mMin)) * fCWidth), (fLast.Y) * fCHeight), New PointF((((fCurrent.X - mMin) / (mMax - mMin)) * fCWidth), (fCurrent.Y) * fCHeight))
                            End If
                            fLast = fCurrent
                        Next
                        b.Dispose()
                        p.Dispose()
                    End If
                End If
            Next
        End If
        ' g.Transform = New Matrix()
        Me.ResumeLayout()
    End Sub
    Private Sub DrawLedgend(ByRef g As Graphics)
        Dim fCount As Integer
        Dim fYcount As Integer
        Dim fColour As Color
        For Each item As libGraph2Ditems In mItems
            If item.Display Then
                fCount += 1
            End If
        Next
        If fCount > 0 Then
            g.SmoothingMode = SmoothingMode.None
            g.InterpolationMode = InterpolationMode.Default
            Dim b As SolidBrush = New SolidBrush(Color.FromArgb(128, (Brightness(mBgColour, 80))))
            Dim p As Pen = New Pen(Brightness(bgColour, 75))
            g.FillRectangle(b, New Rectangle(5, 5, 70, 8 + (12 * fCount)))
            g.DrawRectangle(p, New Rectangle(5, 5, 70, 8 + (12 * fCount)))
            b.Dispose()
            p.Dispose()

            g.TextContrast = 4
            Dim stringFormat As New StringFormat
            stringFormat.Alignment = StringAlignment.Near
            stringFormat.LineAlignment = StringAlignment.Center
            g.TextRenderingHint = Drawing.Text.TextRenderingHint.AntiAliasGridFit
            If Not mItems Is Nothing AndAlso mItems.Count > 0 Then
                For Each item As libGraph2Ditems In mItems
                    If item.Display Then
                        fColour = item.Colour
                        b = New SolidBrush(fColour)
                        g.FillRectangle(b, New Rectangle(13, 10 + (12 * fYcount), 10, 10))
                        g.DrawString(item.Name, New Font(Me.Font, FontStyle.Bold), New SolidBrush(Color.Black), 30, 10 + (12 * fYcount) + 5, stringFormat)
                        fYcount += 1
                        b.Dispose()
                    End If
                Next
            End If
        End If
    End Sub
    Private Sub DrawSelection(ByVal e As System.Windows.Forms.PaintEventArgs)
        If Not mSelectMin = Nothing And Not mSelectMax = Nothing Then
            Dim g As Graphics = e.Graphics
            Dim b As SolidBrush = New SolidBrush(mSelectionColour)
            Dim p As Pen = New Pen(Brightness(mSelectionColour, 80))

            Dim fX1 As Single = (((mSelectMin.X - Min) / (Max - Min)) * mGraphArea.Width)
            Dim fX2 As Single = (((mSelectMax.X - Min) / (Max - Min)) * mGraphArea.Width)
            g.Clip = New Region(e.ClipRectangle)


            If fX1 < fX2 Then
                g.FillRectangle(b, New RectangleF(fX1, 1, fX2 - fX1, mGraphArea.Height - 1))
                g.DrawRectangle(p, New Rectangle(fX1, 1, fX2 - fX1, mGraphArea.Height - 1))
            Else
                g.FillRectangle(b, New RectangleF(fX2, 1, fX1 - fX2, mGraphArea.Height - 1))
                g.DrawRectangle(p, New Rectangle(fX2, 1, fX1 - fX2, mGraphArea.Height - 1))
            End If

            b.Dispose()
            p.Dispose()
        End If
    End Sub

    Public Property Max() As Long
        Get
            Return mMax
        End Get
        Set(ByVal value As Long)
            mMax = value
            Range = Max - Min
            'Me.Refresh()
        End Set
    End Property
    Public Property Min() As Long
        Get
            Return mMin
        End Get
        Set(ByVal value As Long)
            mMin = value
            Range = Max - Min
            ' Me.Refresh()
        End Set
    End Property
    Friend Sub setRange(ByVal xMin As Long, ByVal xMax As Long)
        mMin = xMin
        mMax = xMax
        Me.Refresh()
    End Sub
    ''' <summary>
    ''' Set the view to the Left from the cursorX and by the given Range
    ''' </summary>
    ''' <remarks></remarks>
    Friend Sub setLeft(Optional ByVal noBarSet As Boolean = False)
        mMin = mTrackX - Range
        mMax = mTrackX
        If noBarSet = False Then Me.sbTrackSetRange()
        If mMax <= sbTrack.Maximum And mMax >= sbTrack.Minimum Then
            sbTrack.Value = mMax
        End If
        ' Me.InvokePaint(Me, New System.Windows.Forms.PaintEventArgs(Me.CreateGraphics, mGraphArea))
        Me.Refresh()
    End Sub
    ''' <summary>
    ''' Set the view to the Right from the cursorX and by the given Range
    ''' </summary>
    ''' <remarks></remarks>
    Friend Sub setRight()
        mMax = mTrackX + Range
        mMin = mTrackX
        If mMax <= sbTrack.Maximum And mMax >= sbTrack.Minimum Then
            sbTrack.Value = mMax
        End If
        Me.Refresh()
        'Me.InvokePaint(Me, New System.Windows.Forms.PaintEventArgs(Me.CreateGraphics, mGraphArea))
    End Sub
    Friend Sub setCenter()
        If mTrackX - (Range / 2) > 0 Then
            If mTrackX + (Range / 2) > mStreamMax Then
                mMax = mStreamMax
                mMin = mStreamMax - Range
            Else
                mMin = mTrackX - (Range / 2)
                mMax = mTrackX + (Range / 2)
            End If
        Else
            mMin = 0
            mMax = Range
        End If
        If mMax <= sbTrack.Maximum And mMax >= sbTrack.Minimum Then
            sbTrack.Value = mMax
        End If
        mTrackX = mMax
        Me.Refresh()
    End Sub

    Private Class libGraph2Ditems
        Inherits ArrayList
        Private mName As String = ""
        Private mColour As Color = Color.Black
        Private mWidth As Single = 1
        Private mMax As Single = 100
        Private mMin As Single = 0
        Private mCursorMode As Boolean = False
        Private mCursor As PointF = Nothing
        Private mToolTipText As String = ""
        Private mDisplay As Boolean = False

        Default Public Shadows Property Item(ByVal index As Integer) As PointF
            Get
                Return MyBase.Item(index)
            End Get
            Set(ByVal value As PointF)
                MyBase.Item(index) = value
            End Set
        End Property
       
        Public Shadows Function Add(ByVal value As PointF) As Integer
            value.Y = 0.95 - (((value.Y - mMin) / (mMax - mMin)) * 0.95)
            Return MyBase.Add(value)
        End Function
        Public Property Name() As String
            Get
                Return mName
            End Get
            Set(ByVal value As String)
                mName = value
            End Set
        End Property
        Public Property Colour() As Color
            Get
                Return mColour
            End Get
            Set(ByVal value As Color)
                mColour = value
            End Set
        End Property
        Public Property Width() As Single
            Get
                Return mWidth
            End Get
            Set(ByVal value As Single)
                mWidth = value
            End Set
        End Property
        Public Property Max() As Single
            Get
                Return mMax
            End Get
            Set(ByVal value As Single)
                mMax = value
            End Set
        End Property
        Public Property Min() As Single
            Get
                Return mMin
            End Get
            Set(ByVal value As Single)
                mMin = value
            End Set
        End Property
        Public Property Display() As Boolean
            Get
                Return mDisplay
            End Get
            Set(ByVal value As Boolean)
                mDisplay = value
            End Set
        End Property
        Public Property Cursor() As PointF
            Get
                Return mCursor
            End Get
            Set(ByVal value As PointF)
                mCursor = value
                mCursor.Y = (value.Y - mMin) / (mMax - mMin)
            End Set
        End Property
        Public Property CursorMode() As Boolean
            Get
                Return mCursorMode
            End Get
            Set(ByVal value As Boolean)
                mCursorMode = value
            End Set
        End Property
        Public Property ToolTip() As String
            Get
                Return mToolTipText
            End Get
            Set(ByVal value As String)
                mToolTipText = value
            End Set
        End Property
        Friend Sub setCursor(ByVal point As PointF, Optional ByVal text As String = "")
            mCursor = point
            mCursor.Y = (point.Y - mMin) / (mMax - mMin)
            mToolTipText = text
        End Sub
    End Class

    Private Sub libGraph2D_Resize(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Resize
        Me.Refresh()
    End Sub
    Private Sub libGraph2D_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        CheckScrolls()
    End Sub
    Private Sub cmSelectItems_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmIafm.Click, cmIbcsol.Click, cmIload.Click, cmIrpm.Click, cmIspeed.Click, cmItps.Click, cmItemp.Click, cmIignition.Click, cmInjector.Click, cmAD3.Click, cmAD2.Click, cmAD1.Click, cmBK04.Click, cmBK03.Click, cmBK02.Click, cmBK01.Click
        Dim fMItem As ToolStripMenuItem = CType(sender, ToolStripMenuItem)

        If fMItem.CheckState = CheckState.Unchecked Then
            fMItem.CheckState = CheckState.Checked
            If mMenuItems.Contains(CType(fMItem.Tag, String)) Then
                mMenuItems.Remove(CType(fMItem.Tag, String))
            End If
            mMenuItems.Add(CheckState.Checked, CType(fMItem.Tag, String))
        ElseIf fMItem.CheckState = CheckState.Checked Then
            fMItem.CheckState = CheckState.Indeterminate
            If mMenuItems.Contains(CType(fMItem.Tag, String)) Then
                mMenuItems.Remove(CType(fMItem.Tag, String))
            End If
            mMenuItems.Add(CheckState.Indeterminate, CType(fMItem.Tag, String))
        Else
            fMItem.CheckState = CheckState.Unchecked
            ' Remove the item from the collection
            If mMenuItems.Contains(CType(fMItem.Tag, String)) Then
                mMenuItems.Remove(CType(fMItem.Tag, String))
            End If
        End If

        Try
            Dim fGraphItem As libGraph2Ditems = Me.mItems(CType(fMItem.Tag, String))
            If Not IsNothing(fGraphItem) Then
                Dim fItem As libGraph2Ditems = CType(fGraphItem, libGraph2Ditems)

                If Not IsNothing(fItem) Then
                    If fMItem.CheckState = CheckState.Checked Or fMItem.CheckState = CheckState.Indeterminate Then
                        fItem.Display = True
                        If fMItem.CheckState = CheckState.Indeterminate Then
                            fItem.CursorMode = True
                        Else
                            fItem.CursorMode = False
                        End If
                    Else
                        fItem.Display = False
                    End If
                    Me.Refresh()
                End If
            End If
        Catch
            Console.WriteLine("Error setting the graph item")
        End Try
    End Sub
    Private Sub cmSelectItems_Opening(ByVal sender As System.Object, ByVal e As System.ComponentModel.CancelEventArgs) Handles cmSelectItems.Opening
        setMenuItems()
        'Dim objGraphItem As libGraph2Ditems
        'For Each item As ToolStripMenuItem In cmSelectItems.Items
        '    Try
        '        objGraphItem = mItems.Item(item.Tag)
        '        If Not IsNothing(objGraphItem) Then
        '            If objGraphItem.CursorMode Then
        '                item.CheckState = CheckState.Indeterminate
        '            Else
        '                item.Checked = objGraphItem.Display
        '            End If
        '        End If
        '    Catch
        '    End Try
        'Next
    End Sub
    Private Sub cmMainMenu_Opening(ByVal sender As System.Object, ByVal e As System.ComponentModel.CancelEventArgs) Handles cmMainMenu.Opening
        cnMainSelect.Checked = SelectMode
        If SelectMode Then cmMDelete.Enabled = True Else cmMDelete.Enabled = False
    End Sub

    Private Sub cnMainSelect_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cnMainSelect.Click
        If cnMainSelect.Checked Then
            Me.SelectMode = True
        Else
            Me.SelectMode = False
        End If
    End Sub
    Private Sub cmMDelete_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmMDelete.Click
        If Me.SelectMode And Not IsNothing(mSelectMin) And Not IsNothing(mSelectMax) Then
            RaiseEvent onDeleteSelection(Me, mSelectMin.X, mSelectMax.X)
            SelectMode = False
        End If
    End Sub
End Class


